// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4065)
#endif

#include "mojo/public/interfaces/bindings/interface_control_messages.mojom-shared.h"

#include <utility>

#include "base/logging.h"
#include "mojo/public/cpp/bindings/lib/validate_params.h"
#include "mojo/public/cpp/bindings/lib/validation_context.h"
#include "mojo/public/cpp/bindings/lib/validation_errors.h"
#include "mojo/public/cpp/bindings/lib/validation_util.h"
namespace mojo {
namespace interface_control {

    namespace internal {
        // static
        bool RunInput_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context,
            bool inlined)
        {
            if (!data) {
                DCHECK(!inlined);
                return true;
            }

            // If it is inlined, the alignment is already enforced by its enclosing
            // object. We don't have to validate that.
            DCHECK(!inlined || mojo::internal::IsAligned(data));

            if (!inlined && !mojo::internal::ValidateNonInlinedUnionHeaderAndClaimMemory(data, validation_context)) {
                return false;
            }

            const RunInput_Data* object = static_cast<const RunInput_Data*>(data);
            ALLOW_UNUSED_LOCAL(object);

            if (inlined && object->is_null())
                return true;

            switch (object->tag) {

            case RunInput_Tag::QUERY_VERSION: {

                if (!mojo::internal::ValidatePointerNonNullable(
                        object->data.f_query_version, "null query_version field in RunInput",
                        validation_context)) {
                    return false;
                }
                if (!mojo::internal::ValidateStruct(object->data.f_query_version, validation_context))
                    return false;
                return true;
            }
            case RunInput_Tag::FLUSH_FOR_TESTING: {

                if (!mojo::internal::ValidatePointerNonNullable(
                        object->data.f_flush_for_testing, "null flush_for_testing field in RunInput",
                        validation_context)) {
                    return false;
                }
                if (!mojo::internal::ValidateStruct(object->data.f_flush_for_testing, validation_context))
                    return false;
                return true;
            }
            default: {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNKNOWN_UNION_TAG,
                    "unknown tag in RunInput");
                return false;
            }
            }
        }
        // static
        bool RunOutput_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context,
            bool inlined)
        {
            if (!data) {
                DCHECK(!inlined);
                return true;
            }

            // If it is inlined, the alignment is already enforced by its enclosing
            // object. We don't have to validate that.
            DCHECK(!inlined || mojo::internal::IsAligned(data));

            if (!inlined && !mojo::internal::ValidateNonInlinedUnionHeaderAndClaimMemory(data, validation_context)) {
                return false;
            }

            const RunOutput_Data* object = static_cast<const RunOutput_Data*>(data);
            ALLOW_UNUSED_LOCAL(object);

            if (inlined && object->is_null())
                return true;

            switch (object->tag) {

            case RunOutput_Tag::QUERY_VERSION_RESULT: {

                if (!mojo::internal::ValidatePointerNonNullable(
                        object->data.f_query_version_result, "null query_version_result field in RunOutput",
                        validation_context)) {
                    return false;
                }
                if (!mojo::internal::ValidateStruct(object->data.f_query_version_result, validation_context))
                    return false;
                return true;
            }
            default: {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNKNOWN_UNION_TAG,
                    "unknown tag in RunOutput");
                return false;
            }
            }
        }
        // static
        bool RunOrClosePipeInput_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context,
            bool inlined)
        {
            if (!data) {
                DCHECK(!inlined);
                return true;
            }

            // If it is inlined, the alignment is already enforced by its enclosing
            // object. We don't have to validate that.
            DCHECK(!inlined || mojo::internal::IsAligned(data));

            if (!inlined && !mojo::internal::ValidateNonInlinedUnionHeaderAndClaimMemory(data, validation_context)) {
                return false;
            }

            const RunOrClosePipeInput_Data* object = static_cast<const RunOrClosePipeInput_Data*>(data);
            ALLOW_UNUSED_LOCAL(object);

            if (inlined && object->is_null())
                return true;

            switch (object->tag) {

            case RunOrClosePipeInput_Tag::REQUIRE_VERSION: {

                if (!mojo::internal::ValidatePointerNonNullable(
                        object->data.f_require_version, "null require_version field in RunOrClosePipeInput",
                        validation_context)) {
                    return false;
                }
                if (!mojo::internal::ValidateStruct(object->data.f_require_version, validation_context))
                    return false;
                return true;
            }
            case RunOrClosePipeInput_Tag::SEND_DISCONNECT_REASON: {

                if (!mojo::internal::ValidatePointerNonNullable(
                        object->data.f_send_disconnect_reason, "null send_disconnect_reason field in RunOrClosePipeInput",
                        validation_context)) {
                    return false;
                }
                if (!mojo::internal::ValidateStruct(object->data.f_send_disconnect_reason, validation_context))
                    return false;
                return true;
            }
            default: {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNKNOWN_UNION_TAG,
                    "unknown tag in RunOrClosePipeInput");
                return false;
            }
            }
        }

        // static
        bool RunMessageParams_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context)
        {
            if (!data)
                return true;

            if (!ValidateStructHeaderAndClaimMemory(data, validation_context))
                return false;

            // NOTE: The memory backing |object| may be smaller than |sizeof(*object)| if
            // the message comes from an older version.
            const RunMessageParams_Data* object = static_cast<const RunMessageParams_Data*>(data);

            static constexpr struct {
                uint32_t version;
                uint32_t num_bytes;
            } kVersionSizes[] = { { 0, 24 } };

            if (object->header_.version <= kVersionSizes[arraysize(kVersionSizes) - 1].version) {
                // Scan in reverse order to optimize for more recent versions.
                for (int i = arraysize(kVersionSizes) - 1; i >= 0; --i) {
                    if (object->header_.version >= kVersionSizes[i].version) {
                        if (object->header_.num_bytes == kVersionSizes[i].num_bytes)
                            break;

                        ReportValidationError(
                            validation_context,
                            mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                        return false;
                    }
                }
            } else if (object->header_.num_bytes < kVersionSizes[arraysize(kVersionSizes) - 1].num_bytes) {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                return false;
            }

            if (!mojo::internal::ValidateInlinedUnionNonNullable(
                    object->input, "null input field in RunMessageParams",
                    validation_context)) {
                return false;
            }
            if (!mojo::internal::ValidateInlinedUnion(object->input, validation_context))
                return false;

            return true;
        }

        // static
        bool RunResponseMessageParams_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context)
        {
            if (!data)
                return true;

            if (!ValidateStructHeaderAndClaimMemory(data, validation_context))
                return false;

            // NOTE: The memory backing |object| may be smaller than |sizeof(*object)| if
            // the message comes from an older version.
            const RunResponseMessageParams_Data* object = static_cast<const RunResponseMessageParams_Data*>(data);

            static constexpr struct {
                uint32_t version;
                uint32_t num_bytes;
            } kVersionSizes[] = { { 0, 24 } };

            if (object->header_.version <= kVersionSizes[arraysize(kVersionSizes) - 1].version) {
                // Scan in reverse order to optimize for more recent versions.
                for (int i = arraysize(kVersionSizes) - 1; i >= 0; --i) {
                    if (object->header_.version >= kVersionSizes[i].version) {
                        if (object->header_.num_bytes == kVersionSizes[i].num_bytes)
                            break;

                        ReportValidationError(
                            validation_context,
                            mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                        return false;
                    }
                }
            } else if (object->header_.num_bytes < kVersionSizes[arraysize(kVersionSizes) - 1].num_bytes) {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                return false;
            }

            if (!mojo::internal::ValidateInlinedUnion(object->output, validation_context))
                return false;

            return true;
        }

        // static
        bool QueryVersion_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context)
        {
            if (!data)
                return true;

            if (!ValidateStructHeaderAndClaimMemory(data, validation_context))
                return false;

            // NOTE: The memory backing |object| may be smaller than |sizeof(*object)| if
            // the message comes from an older version.
            const QueryVersion_Data* object = static_cast<const QueryVersion_Data*>(data);

            static constexpr struct {
                uint32_t version;
                uint32_t num_bytes;
            } kVersionSizes[] = { { 0, 8 } };

            if (object->header_.version <= kVersionSizes[arraysize(kVersionSizes) - 1].version) {
                // Scan in reverse order to optimize for more recent versions.
                for (int i = arraysize(kVersionSizes) - 1; i >= 0; --i) {
                    if (object->header_.version >= kVersionSizes[i].version) {
                        if (object->header_.num_bytes == kVersionSizes[i].num_bytes)
                            break;

                        ReportValidationError(
                            validation_context,
                            mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                        return false;
                    }
                }
            } else if (object->header_.num_bytes < kVersionSizes[arraysize(kVersionSizes) - 1].num_bytes) {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                return false;
            }

            return true;
        }

        // static
        bool QueryVersionResult_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context)
        {
            if (!data)
                return true;

            if (!ValidateStructHeaderAndClaimMemory(data, validation_context))
                return false;

            // NOTE: The memory backing |object| may be smaller than |sizeof(*object)| if
            // the message comes from an older version.
            const QueryVersionResult_Data* object = static_cast<const QueryVersionResult_Data*>(data);

            static constexpr struct {
                uint32_t version;
                uint32_t num_bytes;
            } kVersionSizes[] = { { 0, 16 } };

            if (object->header_.version <= kVersionSizes[arraysize(kVersionSizes) - 1].version) {
                // Scan in reverse order to optimize for more recent versions.
                for (int i = arraysize(kVersionSizes) - 1; i >= 0; --i) {
                    if (object->header_.version >= kVersionSizes[i].version) {
                        if (object->header_.num_bytes == kVersionSizes[i].num_bytes)
                            break;

                        ReportValidationError(
                            validation_context,
                            mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                        return false;
                    }
                }
            } else if (object->header_.num_bytes < kVersionSizes[arraysize(kVersionSizes) - 1].num_bytes) {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                return false;
            }

            return true;
        }

        // static
        bool FlushForTesting_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context)
        {
            if (!data)
                return true;

            if (!ValidateStructHeaderAndClaimMemory(data, validation_context))
                return false;

            // NOTE: The memory backing |object| may be smaller than |sizeof(*object)| if
            // the message comes from an older version.
            const FlushForTesting_Data* object = static_cast<const FlushForTesting_Data*>(data);

            static constexpr struct {
                uint32_t version;
                uint32_t num_bytes;
            } kVersionSizes[] = { { 0, 8 } };

            if (object->header_.version <= kVersionSizes[arraysize(kVersionSizes) - 1].version) {
                // Scan in reverse order to optimize for more recent versions.
                for (int i = arraysize(kVersionSizes) - 1; i >= 0; --i) {
                    if (object->header_.version >= kVersionSizes[i].version) {
                        if (object->header_.num_bytes == kVersionSizes[i].num_bytes)
                            break;

                        ReportValidationError(
                            validation_context,
                            mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                        return false;
                    }
                }
            } else if (object->header_.num_bytes < kVersionSizes[arraysize(kVersionSizes) - 1].num_bytes) {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                return false;
            }

            return true;
        }

        // static
        bool RunOrClosePipeMessageParams_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context)
        {
            if (!data)
                return true;

            if (!ValidateStructHeaderAndClaimMemory(data, validation_context))
                return false;

            // NOTE: The memory backing |object| may be smaller than |sizeof(*object)| if
            // the message comes from an older version.
            const RunOrClosePipeMessageParams_Data* object = static_cast<const RunOrClosePipeMessageParams_Data*>(data);

            static constexpr struct {
                uint32_t version;
                uint32_t num_bytes;
            } kVersionSizes[] = { { 0, 24 } };

            if (object->header_.version <= kVersionSizes[arraysize(kVersionSizes) - 1].version) {
                // Scan in reverse order to optimize for more recent versions.
                for (int i = arraysize(kVersionSizes) - 1; i >= 0; --i) {
                    if (object->header_.version >= kVersionSizes[i].version) {
                        if (object->header_.num_bytes == kVersionSizes[i].num_bytes)
                            break;

                        ReportValidationError(
                            validation_context,
                            mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                        return false;
                    }
                }
            } else if (object->header_.num_bytes < kVersionSizes[arraysize(kVersionSizes) - 1].num_bytes) {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                return false;
            }

            if (!mojo::internal::ValidateInlinedUnionNonNullable(
                    object->input, "null input field in RunOrClosePipeMessageParams",
                    validation_context)) {
                return false;
            }
            if (!mojo::internal::ValidateInlinedUnion(object->input, validation_context))
                return false;

            return true;
        }

        // static
        bool RequireVersion_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context)
        {
            if (!data)
                return true;

            if (!ValidateStructHeaderAndClaimMemory(data, validation_context))
                return false;

            // NOTE: The memory backing |object| may be smaller than |sizeof(*object)| if
            // the message comes from an older version.
            const RequireVersion_Data* object = static_cast<const RequireVersion_Data*>(data);

            static constexpr struct {
                uint32_t version;
                uint32_t num_bytes;
            } kVersionSizes[] = { { 0, 16 } };

            if (object->header_.version <= kVersionSizes[arraysize(kVersionSizes) - 1].version) {
                // Scan in reverse order to optimize for more recent versions.
                for (int i = arraysize(kVersionSizes) - 1; i >= 0; --i) {
                    if (object->header_.version >= kVersionSizes[i].version) {
                        if (object->header_.num_bytes == kVersionSizes[i].num_bytes)
                            break;

                        ReportValidationError(
                            validation_context,
                            mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                        return false;
                    }
                }
            } else if (object->header_.num_bytes < kVersionSizes[arraysize(kVersionSizes) - 1].num_bytes) {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                return false;
            }

            return true;
        }

        // static
        bool SendDisconnectReason_Data::Validate(
            const void* data,
            mojo::internal::ValidationContext* validation_context)
        {
            if (!data)
                return true;

            if (!ValidateStructHeaderAndClaimMemory(data, validation_context))
                return false;

            // NOTE: The memory backing |object| may be smaller than |sizeof(*object)| if
            // the message comes from an older version.
            const SendDisconnectReason_Data* object = static_cast<const SendDisconnectReason_Data*>(data);

            static constexpr struct {
                uint32_t version;
                uint32_t num_bytes;
            } kVersionSizes[] = { { 0, 24 } };

            if (object->header_.version <= kVersionSizes[arraysize(kVersionSizes) - 1].version) {
                // Scan in reverse order to optimize for more recent versions.
                for (int i = arraysize(kVersionSizes) - 1; i >= 0; --i) {
                    if (object->header_.version >= kVersionSizes[i].version) {
                        if (object->header_.num_bytes == kVersionSizes[i].num_bytes)
                            break;

                        ReportValidationError(
                            validation_context,
                            mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                        return false;
                    }
                }
            } else if (object->header_.num_bytes < kVersionSizes[arraysize(kVersionSizes) - 1].num_bytes) {
                ReportValidationError(
                    validation_context,
                    mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
                return false;
            }

            if (!mojo::internal::ValidatePointerNonNullable(
                    object->description, "null description field in SendDisconnectReason",
                    validation_context)) {
                return false;
            }
            const mojo::internal::ContainerValidateParams description_validate_params(
                0, false, nullptr);
            if (!mojo::internal::ValidateContainer(object->description, validation_context,
                    &description_validate_params)) {
                return false;
            }

            return true;
        }

    } // namespace internal
} // namespace interface_control
} // namespace mojo

#if defined(_MSC_VER)
#pragma warning(pop)
#endif
